require('luapl')
require('luaunit')

-- ///////////////////////////////////////////////////////////////////////////
-- // Benchmark tests
-- ///////////////////////////////////////////////////////////////////////////

TestBM = {}

function TestBM:testuniq()
-- remove duplicates benchmark
--  local x = A(1000000,2,2,shape,rand,4000000,shape,100)
  local x = A(rand,400000,shape,100)
  local lx = x:value()
  local st = os.clock()
  local z = A(uniq,x)
  local fin1 = os.clock()
  local z1 = luniq(lx)
  local fin2 = os.clock()
  assert((#z)==(#z1))
  print("APL " .. fin1-st .. " LUA " .. fin2-fin1)
end

function TestBM:testmmult()
-- test matrix multiplication
  local msize = 100
  local x = A(til,msize,msize)
  local y = A(til,msize,msize)
  local x1 = x:value()
  local y1 = y:value()
  local st = os.clock()
  local z = A(x,inner,y)
  local fin1 = os.clock()
  local z1 = mmult(msize,msize,x1,y1)
  local fin2 = os.clock()
  assert(z == A(disclose,z1))
  print("APL " .. fin1-st .. " LUA " .. fin2-fin1)
end

function TestBM:testcnd()
-- test cummulative normal distribution function
  local size = 100000
  local st = os.clock()
  local z = cnd(A(til,size)/size)
  local fin1 = os.clock()
  local z1 = {}
  for i=1,size do
    z1[i] = luacnd((i-1)/size)
  end
  local fin2 = os.clock()
  assert(z==A(z1))
  print("APL " .. fin1-st .. " LUA " .. fin2-fin1)
end

-- ///////////////////////////////////////////////////////////////////////////
-- // Functions
-- ///////////////////////////////////////////////////////////////////////////

function luniq(x)
  local flags={}
  local res={}
  local count=1
  for i=1,#x do
    if not flags[x[i]] then
      flags[x[i]] = true
      res[count] = x[i]
      count = count + 1
    end
  end
  return res
end

function mmult(rows, cols, m1, m2)
  local m3 = {}
  for i=1,rows do
    local m3i = {}
    m3[i] = m3i
    local m1i = m1[i]
    for j=1,cols do
      local rowj = 0
      for k=1,cols do
        rowj = rowj + m1i[k] * m2[k][j]
      end
      m3i[j] = rowj
    end
  end
  return(m3)
end

function luacnd(x)
  -- taylor series coefficients
  local a1, a2, a3, a4, a5 = 0.31938153, -0.356563782, 1.781477937,-1.821255978, 1.330274429
  local l = math.abs(x)
  local k = 1.0 / (1.0 + 0.2316419 * l)
  local w = 1.0 - 1.0 / math.sqrt(2 * math.pi) * math.exp(-l * l / 2) * (a1 * k + a2 * k * k + a3 * math.pow(k, 3) + a4 * math.pow(k, 4) + a5 * math.pow(k, 5))
  if x < 0 then w = 1.0 - w end
  return w
end

-- LuaUnit:run('TestLuaBinding:test_setline') -- will execute only one test
-- LuaUnit:run('TestLuaBinding') -- will execute only one class of test
-- LuaUnit.result.verbosity = 0
LuaUnit:run()
print("Press any key to exit")
io.read()